//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioControls.RegistryManagerModule
{
    using System;
    using System.Windows;
    using System.Windows.Input;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Research.Authentication;
    using Microsoft.Practices.Unity;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using System.Globalization;

    /// <summary>
    /// Presenter logic for Add Credential UI
    /// </summary>
    public class AddCredentialPresenter : INotifyPropertyChanged
    {
        /// <summary>
        /// 
        /// </summary>
        private AddCredential addUserWindow;

        /// <summary>
        /// 
        /// </summary>
        private CredentialType selectType;

        /// <summary>
        /// 
        /// </summary>
        private string credentialLabel;

        /// <summary>
        /// 
        /// </summary>
        private string credentialTitle;

        /// <summary>
        /// Add User command.
        /// </summary>
        public DelegateCommand<object> AddCommand { get; set; }

        /// <summary>
        /// Cancel User command.
        /// </summary>
        public DelegateCommand<object> CancelCommand { get; set; }

        /// <summary>
        /// Test User command.
        /// </summary>
        public DelegateCommand<object> TestCommand { get; set; }

        /// <summary>
        /// Show Add User command.
        /// </summary>
        public DelegateCommand<CredentialType> ShowCommand { get; set; }

        /// <summary>
        /// Gets or sets the credential.
        /// </summary>
        /// <value>The credential.</value>
        public ICredentials Credential { get; set; }

        /// <summary>
        /// Name Changes command.
        /// </summary>
        public DelegateCommand<object> NameChangesCommand { get; set; }

        /// <summary>
        /// Gets or sets the editable credential model.
        /// </summary>
        /// <value>The editable credential model.</value>
        public CredentialModel EditableCredentialModel { get; set; }

        /// <summary>
        /// Gets or sets the type of the select.
        /// </summary>
        /// <value>The type of the select.</value>
        private CredentialType SelectType
        {
            get
            {
                return this.selectType;
            }
            set
            {
                this.selectType = value;
                this.CredentialLabel = string.Format(CultureInfo.CurrentCulture, "{0} Credential: ", this.selectType.ToString());
                this.CredentialTitle = string.Format(CultureInfo.CurrentCulture, "Add {0} Credential", this.selectType.ToString());
                this.OnPropertyChanged("SelectType");
            }
        }

        /// <summary>
        /// Gets or sets the credential label.
        /// </summary>
        /// <value>The credential label.</value>
        public string CredentialLabel
        {
            get
            {
                return this.credentialLabel;
            }
            set
            {
                this.credentialLabel = value;
                this.OnPropertyChanged("CredentialLabel");
            }
        }

        /// <summary>
        /// Gets or sets the credential title.
        /// </summary>
        /// <value>The credential title.</value>
        public string CredentialTitle
        {
            get
            {
                return this.credentialTitle;
            }
            set
            {
                this.credentialTitle = value;
                this.OnPropertyChanged("CredentialTitle");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Initializes a new instance of the <see cref="AddCredentialPresenter"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        public AddCredentialPresenter(IUnityContainer container)
        {
            this.container = container;

            this.AddCommand = new DelegateCommand<object>(p => this.AddCommandExecuted());
            this.ShowCommand = new DelegateCommand<CredentialType>(this.ShowCommandExecuted);
            this.CancelCommand = new DelegateCommand<object>(p => this.CancelCommandExecuted());
            this.TestCommand = new DelegateCommand<object>(p => this.TestCommandExecuted(), this.CanExecuteTest);
            this.EditableCredentialModel = new CredentialModel();
            this.EditableCredentialModel.DisplayName = ManagementStudioResourceManager.GetString("NotApplicable");
            this.NameChangesCommand = new DelegateCommand<object>(p => this.NameChangeCommandExecuted());
        }

        /// <summary>
        /// Handler for Adding New User
        /// </summary>
        private void AddCommandExecuted()
        {
            this.ValidateCredential();
            if (this.EditableCredentialModel.IsTestSucceeded)
            {
                this.CloseWindow();
            }
        }

        /// <summary>
        /// Handler for Test Command Execute
        /// </summary>
        private void TestCommandExecuted()
        {
            this.ValidateCredential();

        }

        ///// <summary>
        ///// Handler for Test Command Execute
        ///// </summary>
        private void NameChangeCommandExecuted()
        {
            this.RaiseCanExecute();
        }

        /// <summary>
        /// Validates the credential.
        /// </summary>
        private void ValidateCredential()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                ICredentials inputCredential = new Credentials(this.EditableCredentialModel.Name, this.SelectType);

                if (this.SelectType == CredentialType.User)
                {
                    // Check  for back slash - Remove if it contains any and assign to User name
                    this.ValidateUser(inputCredential);
                }
                else
                {
                    this.ValidateGroup(inputCredential);

                }

                if (this.Credential == null)
                {
                    this.EditableCredentialModel.IsTestSucceeded = false;
                    this.EditableCredentialModel.IsTestFailed = true;
                    this.EditableCredentialModel.DisplayName = ManagementStudioResourceManager.GetString("NotApplicable");
                }
                else
                {
                    this.EditableCredentialModel.DisplayName = this.Credential.DisplayName;
                    this.EditableCredentialModel.IsTestSucceeded = true;
                    this.EditableCredentialModel.IsTestFailed = false;
                }
            }
            catch (Exception)
            {
                this.EditableCredentialModel.IsTestSucceeded = false;
                this.EditableCredentialModel.IsTestFailed = true;
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }

        /// <summary>
        /// Validate the Group Credential in the Active directory
        /// Checks the local machine if the domain name is not provided or it s not fount in AD Froset
        /// </summary>
        /// <param name="inputCredential">ICredentials</param>
        private void ValidateGroup(ICredentials inputCredential)
        {
            BaseAuthentication authentication = new ADAuthentication();
            if (this.EditableCredentialModel.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase) != -1)
            {
                inputCredential.UserName = this.EditableCredentialModel.Name.Substring(this.EditableCredentialModel.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1);
                inputCredential.DomainName = this.EditableCredentialModel.Name.Substring(0, this.EditableCredentialModel.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase));
            }
            else
            {
                inputCredential.UserName = this.EditableCredentialModel.Name;
            }

            this.Credential = authentication.GetGroup(inputCredential);
            if (this.Credential == null)
            {
                if (string.IsNullOrEmpty(inputCredential.DomainName))
                {
                    inputCredential.DomainName = Environment.MachineName;
                }
                authentication = new LocalAuthentication();
                this.Credential = authentication.GetGroup(inputCredential);
            }


        }

        /// <summary>
        /// Validate the User Credential in the Active directory
        /// Checks the local machine if the domain name is not provided or it s not fount in AD Froset
        /// </summary>
        /// <param name="inputCredential">ICredentials</param>
        private void ValidateUser(ICredentials inputCredential)
        {
            BaseAuthentication authentication = new ADAuthentication();
            if (this.EditableCredentialModel.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase) != -1)
            {
                inputCredential.UserName = this.EditableCredentialModel.Name.Substring(this.EditableCredentialModel.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1);
                inputCredential.DomainName = this.EditableCredentialModel.Name.Substring(0, this.EditableCredentialModel.Name.IndexOf("\\", StringComparison.OrdinalIgnoreCase));
            }
            else
            {
                inputCredential.UserName = this.EditableCredentialModel.Name;
            }

            this.Credential = authentication.GetUser(inputCredential);
            if (this.Credential == null)
            {
                if (string.IsNullOrEmpty(inputCredential.DomainName))
                {
                    inputCredential.DomainName = Environment.MachineName;
                }

                authentication = new LocalAuthentication();
                this.Credential = authentication.GetUser(inputCredential);
            }
        }

        /// <summary>
        /// Determines whether this instance [can execute test] the specified obj.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns>
        /// 	<c>true</c> if this instance [can execute test] the specified obj; otherwise, <c>false</c>.
        /// </returns>
        private bool CanExecuteTest(object obj)
        {
            if (this.EditableCredentialModel.Name != null)
            {
                if (string.IsNullOrEmpty(this.EditableCredentialModel.Name.Trim()))
                {
                    this.EditableCredentialModel.IsTestSucceeded = false;
                    this.EditableCredentialModel.IsTestFailed = false;
                    return false;
                }
                else
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Raises the can execute.
        /// </summary>
        private void RaiseCanExecute()
        {
            this.TestCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Handler for Showng "Add User" Screen
        /// </summary>
        /// <param name="selectedType">Type of the selected.</param>
        private void ShowCommandExecuted(CredentialType selectedType)
        {
            this.SelectType = selectedType;
            this.addUserWindow = new AddCredential();
            this.addUserWindow.Owner = (Window)this.container.Resolve<IRegionManager>("MainWindow");
            this.addUserWindow.DataContext = this;
            this.addUserWindow.ShowDialog();
        }

        /// <summary>
        /// Handler for Canceling Add User window
        /// </summary>
        private void CancelCommandExecuted()
        {
            if (this.addUserWindow != null)
            {
                this.Credential = null;
                this.CloseWindow();
            }
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        private void CloseWindow()
        {
            this.addUserWindow.Close();
            this.addUserWindow = null;
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Called when [property changed].
        /// </summary>
        /// <param name="name">The name.</param>
        public void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        #endregion
    }
}
